// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#include "stdafx.h"

using namespace Api;
using namespace Client;
using namespace Common;
using namespace Transport;

BOOL APIENTRY DllMain(
    HMODULE module,
    DWORD reason,
    LPVOID reserved)
{
    UNREFERENCED_PARAMETER(module);
    UNREFERENCED_PARAMETER(reserved);

    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


//
// WARNING: 
//
// The signature below MUST exactly match (including the parameter names)
// with the signature generated by MIDL in the FabricClient.h file. 
// Otherwise the linker does not apply the extern "C" specifier and exports 
// this function as C++ name mangled function instead of C style function.
// 
/* [entry] */ HRESULT FabricCreateClient( 
    /* [in] */ USHORT connectionStringsSize,
    /* [size_is][in] */ __RPC__in_ecount_full(connectionStringsSize) const LPCWSTR *connectionStrings,
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();    

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateClientFactory(
        connectionStringsSize,
        connectionStrings,
        factoryPtr);
    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);

    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateLocalClient( 
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();

    FabricNodeConfigSPtr config = std::make_shared<FabricNodeConfig>();

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateLocalClientFactory(config, factoryPtr);
    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);
    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateClient2( 
    /* [in] */ USHORT connectionStringsSize,
    /* [size_is][in] */ __RPC__in_ecount_full(connectionStringsSize) const LPCWSTR *connectionStrings,
	/* [in] */ __RPC__in_opt IFabricServiceNotificationEventHandler *notificationEventHandler,
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();    

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateClientFactory(
        connectionStringsSize,
        connectionStrings,
        WrapperFactory::create_rooted_com_proxy(notificationEventHandler),
        IClientConnectionEventHandlerPtr(),
        factoryPtr);
    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);

    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateLocalClient2( 
	/* [in] */ __RPC__in_opt IFabricServiceNotificationEventHandler *notificationEventHandler,
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();

    FabricNodeConfigSPtr config = std::make_shared<FabricNodeConfig>();

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateLocalClientFactory(
        config,
        RoleMask::None,
        WrapperFactory::create_rooted_com_proxy(notificationEventHandler),
        IClientConnectionEventHandlerPtr(),
        factoryPtr);
    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);
    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateClient3( 
    /* [in] */ USHORT connectionStringsSize,
    /* [size_is][in] */ __RPC__in_ecount_full(connectionStringsSize) const LPCWSTR *connectionStrings,
	/* [in] */ __RPC__in_opt IFabricServiceNotificationEventHandler *notificationEventHandler,
	/* [in] */ __RPC__in_opt IFabricClientConnectionEventHandler *connectionEventHandler,
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();    

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateClientFactory(
        connectionStringsSize,
        connectionStrings,
        WrapperFactory::create_rooted_com_proxy(notificationEventHandler),
        WrapperFactory::create_rooted_com_proxy(connectionEventHandler),
        factoryPtr);
    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);

    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateLocalClient3( 
	/* [in] */ __RPC__in_opt IFabricServiceNotificationEventHandler *notificationEventHandler,
	/* [in] */ __RPC__in_opt IFabricClientConnectionEventHandler *connectionEventHandler,
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();

    FabricNodeConfigSPtr config = std::make_shared<FabricNodeConfig>();

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateLocalClientFactory(
        config,
        RoleMask::None,
        WrapperFactory::create_rooted_com_proxy(notificationEventHandler),
        WrapperFactory::create_rooted_com_proxy(connectionEventHandler),
        factoryPtr);
    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);
    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT FabricCreateLocalClient4(
    /* [in] */ __RPC__in_opt IFabricServiceNotificationEventHandler *notificationEventHandler,
    /* [in] */ __RPC__in_opt IFabricClientConnectionEventHandler *connectionEventHandler,
    /* [in] */ FABRIC_CLIENT_ROLE clientRole,
    /* [in] */ __RPC__in REFIID iid,
    /* [retval][out] */ __RPC__deref_out_opt void **fabricClient)
{
    DllConfig::GetConfig();

    RoleMask::Enum roleMask;
    auto errCode = RoleMask::TryParse(clientRole, roleMask);

    if (!errCode.IsSuccess()) { return ComUtility::OnPublicApiReturn(errCode.ToHResult()); }

    FabricNodeConfigSPtr config = std::make_shared<FabricNodeConfig>();

    IClientFactoryPtr factoryPtr;
    auto error = Client::ClientFactory::CreateLocalClientFactory(
        config,
        roleMask,
        WrapperFactory::create_rooted_com_proxy(notificationEventHandler),
        WrapperFactory::create_rooted_com_proxy(connectionEventHandler),
        factoryPtr);

    if (!error.IsSuccess()) { return ComUtility::OnPublicApiReturn(error.ToHResult()); }

    ComPointer<ComFabricClient> comClient;
    auto hr = ComFabricClient::CreateComFabricClient(factoryPtr, comClient);

    if (FAILED(hr)) { return ComUtility::OnPublicApiReturn(hr); }

    hr = comClient->QueryInterface(iid, fabricClient);
    return ComUtility::OnPublicApiReturn(hr);
}

/* [entry] */ HRESULT GetFabricClientDefaultSettings( 
    /* [retval][out] */ __RPC__deref_out_opt IFabricClientSettingsResult **result)
{
    if (result == NULL)
    {
        return ComUtility::OnPublicApiReturn(E_POINTER);
    }

    DllConfig::GetConfig();

    auto resultCPtr = make_com<Api::ComClientSettingsResult, IFabricClientSettingsResult>(Client::ClientFactory::GetFabricClientDefaultSettings());
    *result = resultCPtr.DetachNoRelease();

    return S_OK;
}

#if !defined(PLATFORM_UNIX)
/* [entry] */ HRESULT FabricGetClientDllVersion( 
    /* [out] */ __RPC__deref_out_opt IFabricStringResult **clientDllVersion)
{
    DllConfig::GetConfig();

    std::wstring result;
    auto error = Environment::GetCurrentModuleFileVersion2(result);

    if(error.IsSuccess())
    {
        return ComStringResult::ReturnStringResult(result, clientDllVersion);
    }
    else
    {
        return ComUtility::OnPublicApiReturn(error.ToHResult());
    }
}
#endif

/* [entry] */ HRESULT FabricGetDefaultRollingUpgradeMonitoringPolicy(
    /* [retval][out] */ __RPC__deref_out_opt IFabricGetRollingUpgradeMonitoringPolicyResult **result)
{
    if (result == NULL)
    {
        return ComUtility::OnPublicApiReturn(E_POINTER);
    }

    DllConfig::GetConfig();

    auto resultCPtr = make_com<Api::ComGetRollingUpgradeMonitoringPolicyResult, IFabricGetRollingUpgradeMonitoringPolicyResult>(
        ServiceModel::RollingUpgradeMonitoringPolicy::Default);
    *result = resultCPtr.DetachNoRelease();

    return S_OK;
}
